package dyyx.util;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

public class RunStatus {

    public final String                  version        = "devtool 2019-04-03 11:35:00";

    public final String                  defaultCharset = Charset.defaultCharset().name();

    private volatile boolean             debug          = false;

    public final long                    startTime      = System.currentTimeMillis();

    private long                         resetTime      = 0;

    public final HostInfo                hostInfo       = HostInfoUtil.getHostInfo();

    public final Map<String, String>     infoMap        = new ConcurrentHashMap<String, String>();

    private final int                    ERRORS_LEN     = 100;
    private final String[]               errors         = new String[ERRORS_LEN];

    private final AtomicLong             errorSeq       = new AtomicLong(0);

    /**
     * 不会被clear 一直保留
     */
    public final Map<String, String>     staticInfoMap  = new ConcurrentHashMap<String, String>();
    public final Map<String, AtomicLong> countMap       = new ConcurrentHashMap<String, AtomicLong>();

    /**
     * 通用的打点数据 不需要定义字段 根据 key 区分
     */
    public final Map<String, TimeInfo>   timeInfoMap    = new ConcurrentHashMap<String, TimeInfo>();

    public final Map<String, Object>     extraData      = new ConcurrentHashMap<String, Object>();


    public synchronized void reset() {

        infoMap.clear();
        timeInfoMap.clear();
        countMap.clear();

        for (int i = 0; i < ERRORS_LEN; i++) {
            errors[i] = null;
        }

        resetTime = System.currentTimeMillis();
    }

    public String getStartTimeStr() {
        return CommUtil.getDateString(new Date(startTime));
    }

    public String getResetTimeStr() {
        if (resetTime <= 0) {
            return null;
        }
        return CommUtil.getDateString(new Date(resetTime));
    }

    public void updateCount(String key, long delta) {
        if (key==null || delta <= 0) {
            return;
        }
        AtomicLong al = countMap.get(key);
        if (al == null) {
            al = new AtomicLong(0);
            countMap.put(key, al);
        }
        if (delta == 1) {
            al.incrementAndGet();
        } else {
            al.addAndGet(delta);
        }

    }

    public void updateCount(String key) {
        updateCount(key, 1);
    }

    public void updateInfo(String key, String msg) {
        if (CommUtil.isBlank(key) || CommUtil.isBlank(msg)) {
            return;
        }
        infoMap.put(key, msg);
    }

    public void updateStatisInfo(String key, String msg) {
        if (CommUtil.isBlank(key) || CommUtil.isBlank(msg)) {
            return;
        }
        staticInfoMap.put(key, msg);
    }

    public void logError(String tag, Throwable e) {
        int index = fetchErrorInfoIndex();
        Date now = new Date();
        if (tag == null) {
            tag = "0";
        }
        errors[index] = now.getTime() + ":" + tag + ":" + e + ":" + now;
    }

    private int fetchErrorInfoIndex() {

        long tmp = errorSeq.getAndIncrement();
        int inttmp = (int) (tmp % ERRORS_LEN);
        if (inttmp < 0) {
            inttmp = 0 - inttmp;
        }
        return inttmp;
    }

    public List<String> getErrorList() {
        List<String> list = new ArrayList<String>();
        for (String item : errors) {
            if (CommUtil.isBlank(item)) {
                continue;
            }
            list.add(item);
        }
        Collections.sort(list);
        Collections.reverse(list);
        return list;
    }

    public boolean isDebug() {
        return debug;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    public long getResetTime() {
        return resetTime;
    }

    public void setResetTime(long resetTime) {
        this.resetTime = resetTime;
    }
}
